package com.galaxy.service.service.system.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.galaxy.commom.base.exception.RequestException;
import com.galaxy.commom.base.exception.UserException;
import com.galaxy.commom.base.jwt.JwtToken;
import com.galaxy.commom.base.message.ResponseCode;
import com.galaxy.commom.base.utils.Collections3;
import com.galaxy.commom.base.utils.IpUtil;
import com.galaxy.commom.base.utils.Md5EncryptUtil;
import com.galaxy.service.dto.SignInDto;
import com.galaxy.service.dto.system.user.QueryUserDto;
import com.galaxy.service.dto.system.user.ResetPasswordDto;
import com.galaxy.service.dto.system.user.UserAddDto;
import com.galaxy.service.dto.system.user.UserUpdateDto;
import com.galaxy.service.entity.system.Permission;
import com.galaxy.service.entity.system.Role;
import com.galaxy.service.entity.system.User;
import com.galaxy.service.entity.system.UserRole;
import com.galaxy.service.mapper.system.UserMapper;
import com.galaxy.service.service.global.ShiroService;
import com.galaxy.service.service.system.PermissionService;
import com.galaxy.service.service.system.RoleService;
import com.galaxy.service.service.system.UserRoleService;
import com.galaxy.service.service.system.UserService;
import com.galaxy.service.vo.UserVo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 用户接口实现类
 * @author caijinbang
 * @date 2018/10/27 19:14
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {

  @Autowired
  private RoleService roleService;

  @Autowired
  private UserRoleService userRoleService;

  @Autowired
  private ShiroService shiroService;

  @Autowired
  private PermissionService resourceService;

  /**
   * 根据用户名称查询用户
   * @param name 用户名称
   * @param hasResource
   * @return
   */
  @Override
  public User findUserByName(String name,boolean hasResource) {
    User user = this.selectOne(new EntityWrapper<User>().eq("user_name",name));
    if(user == null){
      return null;
    }
    List<Role> roles = roleService.findAllRoleByUserId(user.getId(), hasResource);
    if (Collections3.isNotEmpty(roles)){
      user.setRoles(roles);
    }
    return user;
  }

  /**
   * 根据ID查找用户
   * @param id 用户id
   * @param hasResource
   * @return
   */
  @Override
  public User findUserById(String id,boolean hasResource) {
    User user = this.selectById(id);
    if(user == null){
      return null;
    }
    user.setRoles(roleService.findAllRoleByUserId(user.getId(),false));
    return user;
  }

  /**
   * 用户登录
   * @param signInDto 登录信息
   */
  @Override
  public void signIn(SignInDto signInDto) {
    //登录用户名密码校验
    if( StringUtils.isEmpty(signInDto.getUsername()) || StringUtils.isEmpty(signInDto.getPassword()) ){
      throw new RequestException(ResponseCode.SING_IN_INPUT_EMPTY);
    }
    //token校验
    JwtToken token = new JwtToken(null,signInDto.getUsername(),signInDto.getPassword());
    Subject subject = SecurityUtils.getSubject();
    try {
      subject.login(token);
      if(!subject.isAuthenticated()){
        throw new RequestException(ResponseCode.SIGN_IN_INPUT_FAIL);
      }
    }catch (DisabledAccountException e){
      throw new UserException();
    }catch (Exception e){
      throw new RequestException(ResponseCode.SIGN_IN_FAIL,e);
    }
  }

  /**
   * 获取当前用户
   * @return
   */
  @Override
  public UserVo getCurrentUser(){
    IpUtil.executeLogin();
    Subject subject = SecurityUtils.getSubject();
    if(!subject.isAuthenticated()){
      throw new RequestException(ResponseCode.NOT_SING_IN);
    }
    JwtToken jwtToken = new JwtToken();
    Object principal = subject.getPrincipal();
    if(principal==null){
      throw RequestException.fail("用户信息获取失败");
    }
    BeanUtils.copyProperties(principal,jwtToken);
    User user = this.findUserByName(jwtToken.getUsername(),false);
    if(user==null){
      throw RequestException.fail("用户不存在");
    }
    //获取菜单/权限信息
    List<Permission> allPer = userRolesRegexResource(roleService.findAllRoleByUserId(user.getId(),true));
    UserVo userVo = new UserVo();
    BeanUtils.copyProperties(user,userVo);
    userVo.setPermissions(allPer);
    return userVo;
  }

  /**
   * 获取所有用户全新啊标签
   * @return
   */
  @Override
  public List<String> getAllPermissionTag() {
    IpUtil.executeLogin();
    Subject subject = SecurityUtils.getSubject();
    if(!subject.isAuthenticated()){
      throw new RequestException(ResponseCode.NOT_SING_IN);
    }
    JwtToken jwtToken = new JwtToken();
    Object principal = subject.getPrincipal();
    if(principal==null){
      throw RequestException.fail("用户信息获取失败");
    }
    BeanUtils.copyProperties(principal,jwtToken);
    User user = this.selectOne(new EntityWrapper<User>()
        .eq("username",jwtToken.getUsername())
        .setSqlSelect("id"));
    if(user==null){
      throw RequestException.fail("用户不存在");
    }
    List<Role> allRoleByUserId = roleService.findAllRoleByUserId(user.getId(), true);
    List<String> permissions = new LinkedList<>();
    for (Role sysRole : allRoleByUserId) {
      if(sysRole.getPermissions()!=null && sysRole.getPermissions().size()>0){
        sysRole.getPermissions().forEach(s-> permissions.add(s.getPermission()));
      }
    }
    return permissions;
  }

  /**
   * 用户角色资源匹配
   * @param roles 用户角色集
   * @return
   */
  @Override
  public List<Permission> userRolesRegexResource(List<Role> roles){
    if(roles!=null && roles.size()>0){
      Map<String,Permission> resourceMap = Maps.newLinkedHashMap();
      roles.forEach(role -> {
        if(role.getPermissions()!=null && role.getPermissions().size()>0){
          //含有则不覆盖
          role.getPermissions().forEach(resource ->
              resourceMap.putIfAbsent(resource.getId(), resource));
        }
      });
      Map<String,Permission> cacheMap = Maps.newConcurrentMap();
      List<Permission> resourceList = new CopyOnWriteArrayList<>();
      resourceMap.forEach((k,v)-> {
        Permission allParent = resourceService.getResourceAllParent(v, cacheMap,resourceMap);
        //判断是否已经包含此对象
        if(!resourceList.contains(allParent)){
          resourceList.add(allParent);
        }
      });
      return resourceList;
    }
    return null;
  }

  /**
   * 获取所有用户（分页）
   * @param queryUserDto
   * @return
   */
  @Override
  public Page<UserVo> getAllUserBySplitPage(QueryUserDto queryUserDto) {
    EntityWrapper<User> wrapper = new EntityWrapper<>();
    wrapper.orderBy("create_date",queryUserDto.getAsc());
    Page<User> userPage = this.selectPage(new Page<>(queryUserDto.getPage(),
        queryUserDto.getPageSize()), wrapper);
    Page<UserVo> userVoPage = new Page<>();
    BeanUtils.copyProperties(userPage,userVoPage);
    List<UserVo> userVOS = Lists.newArrayList();
    userPage.getRecords().forEach(v->{
      UserVo vo = new UserVo();
      BeanUtils.copyProperties(v,vo);
      //查找匹配所有用户的角色
      vo.setRoles(roleService.findAllRoleByUserId(v.getId(),false));
      userVOS.add(vo);
    });
    userVoPage.setRecords(userVOS);
    return userVoPage;
  }

  /**
   * 用户状态改变
   * @param userId 用户ID
   * @param status 状态码
   */
  @Override
  public void statusChange(String userId, Integer status) {
    User user = this.selectById(userId);
    if(user==null){
      throw RequestException.fail("用户不存在");
    }
    User changeUser = new User();
    BeanUtils.copyProperties(SecurityUtils.getSubject().getPrincipal(),changeUser);
    if(user.getUserName().equals(changeUser.getUserName())){
      throw RequestException.fail("不能锁定自己的账户");
    }
    user.setStatus(status);
    try {
      this.updateById(user);
      //若为0 需要进行清除登陆授权以及权限信息
            /*if(status==0){

            }*/
      shiroService.clearAuthByUserId(userId,true,true);
    }catch (Exception e){
      throw RequestException.fail("操作失败",e);
    }
  }

  /**
   * 删除用户
   * @param userId 用户ID
   */
  @Override
  public void removeUser(String userId) {
    User user = this.selectById(userId);
    if(user==null){
      throw RequestException.fail("用户不存在！");
    }
    User deleteUser = new User();
    BeanUtils.copyProperties(SecurityUtils.getSubject().getPrincipal(),deleteUser);
    if(user.getUserName().equals(deleteUser.getUserName())){
      throw RequestException.fail("不能删除自己的账户！");
    }
    try {
      this.deleteById(userId);
      shiroService.clearAuthByUserId(userId,true,true);
    }catch (Exception e){
      throw RequestException.fail("删除失败",e);
    }
  }

  @Override
  public void add(UserAddDto userAddDto) {
    User findUser = this.findUserByName(userAddDto.getUsername(),false);
    if(findUser!=null){
      throw RequestException.fail(
          String.format("已经存在用户名为 %s 的用户",userAddDto.getUsername()));
    }
    try {
      findUser = new User();
      BeanUtils.copyProperties(userAddDto,findUser);
      findUser.setCreateDate(new Date());
      findUser.setPassword(Md5EncryptUtil.string2MD5(String.valueOf(findUser.getPassword())+findUser.getUserName()));
      this.insert(findUser);
      this.updateUserRole(findUser);
    }catch (Exception e){
      throw RequestException.fail("添加用户失败",e);
    }
  }

  @Override
  public void update(String id, UserUpdateDto userUpdateDto) {
    User user = this.selectById(id);
    if(user==null){
      throw RequestException.fail(
          String.format("更新失败，不存在ID为 %s 的用户",id));
    }
    User findUser = this.selectOne(new EntityWrapper<User>().eq("user_name",userUpdateDto.getUsername()).ne("id",id));
    if(findUser!=null){
      throw RequestException.fail(
          String.format("更新失败，已经存在用户名为 %s 的用户",userUpdateDto.getUsername()));
    }
    BeanUtils.copyProperties(userUpdateDto,user);
    try {
      this.updateById(user);
      this.updateUserRole(user);
      shiroService.clearAuthByUserId(user.getId(),true,false);
    }catch (RequestException e){
      throw RequestException.fail(e.getMsg(),e);
    }catch (Exception e){
      throw RequestException.fail("用户信息更新失败",e);
    }
  }

  /**
   * 更新用户角色关系
   * @param user
   */
  @Override
  public void updateUserRole(User user) {
    try {
      userRoleService.delete(new EntityWrapper<UserRole>().eq("user_Id",user.getId()));
      if(user.getRoles()!=null && user.getRoles().size()>0){
        user.getRoles().forEach(v-> {
          userRoleService.insert(UserRole.builder().userId(user.getId()).roleId(v.getId()).build());
        });
      }
    }catch (Exception e){
      throw RequestException.fail("用户权限关联失败",e);
    }
  }

  /**
   * 重置用户密码
   * @param resetPasswordDto 重置密码dto
   */
  @Override
  public void resetPassword(ResetPasswordDto resetPasswordDto){
    User user = this.selectById(resetPasswordDto.getUserId().trim());
    if(user==null){
      throw RequestException.fail(String.format("不存在ID为 %s 的用户",resetPasswordDto.getUserId()));
    }
    String password = Md5EncryptUtil.string2MD5(String.valueOf(resetPasswordDto.getPassword())+user.getUserName());
    user.setPassword(password);
    try {
      this.updateById(user);
      shiroService.clearAuthByUserId(user.getId(),true,true);
    }catch (Exception e){
      throw RequestException.fail(String.format("ID为 %s 的用户密码重置失败",resetPasswordDto.getUserId()),e);
    }
  }

}
